package socket

import (
	"encoding/json"
	"fmt"
	"github.com/parnurzeal/gorequest"
	"go.uber.org/zap"
	"log"
	"net/http"
	"qmp_go_push/models"
	"qmp_go_push/pkg/logger"
	"time"

	"github.com/gorilla/websocket"
	"qmp_go_push/conf"
	"qmp_go_push/pkg/response"
)

var (
	clientManager = NewClientManager()
)

func InitServer() {
	http.HandleFunc("/todo/wss", func(writer http.ResponseWriter, request *http.Request) {
		conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
			return true
		}}).Upgrade(writer, request, nil)
		if err != nil {
			http.NotFound(writer, request)
			return
		}

		token := request.URL.Query().Get("token")

		certificate, biz := checkToken(token)
		if biz != response.Success {
			http.Error(writer, biz.Message.Error(), biz.Code)
			return
		}

		client := NewClient(conn.RemoteAddr().String(), conn, uint64(time.Now().Unix()), certificate.Data.UserUuid)
		clientManager.AddUsers(certificate.Data.UserUuid, client)

		go client.read()
		go client.write()

	})

	if err := http.ListenAndServe(fmt.Sprintf(":%d", conf.CONFIG.Server.WebSocketPort), nil); err != nil {
		log.Fatal("Fatal error http.ListenAndServe(webSocketPort int): \n", err.Error())
	}
}

type VerifyTokenReq struct {
	Token string `json:"token"`
}
type VerifyTokenRes struct {
	Data VerifyTokenData `json:"data"`
}

type VerifyTokenData struct {
	UserUuid string `json:"user_uuid"`
	Salt     string `json:"salt"`
	Src      int    `json:"src"`
	Way      int    `json:"way"`
	Env      string `json:"env"`
}

func checkToken(token string) (VerifyTokenRes, response.CustomBizEnum) {
	var (
		res VerifyTokenRes
		req = VerifyTokenReq{
			Token: token,
		}
	)

	_, bodyStr, err := gorequest.New().Post(conf.CONFIG.VerifyToken.VerifyUrl).Type("multipart").Send(req).End()
	if err != nil {
		logger.Info(logger.ErrLogger, "socket checkToken err", zap.Any("req", req), zap.Any("resp", bodyStr), zap.Any("err", fmt.Sprintf("%v", err)))
		return res, response.ErrInvalidToken
	}

	_ = json.Unmarshal([]byte(bodyStr), &res)
	if len(res.Data.UserUuid) == 0 {
		return res, response.ErrInvalidToken
	}

	teamInfo := models.GetTeamInfoByUserUuid(res.Data.UserUuid)
	if len(teamInfo.TeamUuid) == 0 {
		return res, response.ErrNotTeam
	}
	if teamInfo.IsBan > 0 {
		return res, response.ErrUserIsBan
	}
	if teamInfo.IsQuit > 0 {
		return res, response.ErrUserIsQuit
	}
	return res, response.Success
}
